// gameview.cpp
//

#include "gameview.hpp"
#include "renderengine.hpp"
#include "game.hpp"

#include "glm/gtx/rotate_vector.hpp"



// GameView::GameView
//
GameView::GameView ( wtk::Display &display,
                     RenderEngine &engine,
                     Game &game )
  : wtk::Dialog(display),
    engine(engine),
    game(game),
    renderer(engine, game.get_scene())
{
  // [FIXME]
  render_mode_count = engine.get_render_mode_count();
  render_mode = render_mode_count - 1;
  renderer.set_render_mode(render_mode);
}


  
// event_keyboard
//
void GameView::event_keyboard ( const Event &event )
{
  WTK_TRACE("key: %u", event.keyboard.keycode);
  switch (event.keyboard.type)
    {
    case EventType::KeyDown:
      switch (event.keyboard.keycode)
        {
        case SDLK_c:
          cam[active_cam].camera->set_active(false);
          active_cam = (active_cam + 1) % n_cameras;
          cam[active_cam].camera->set_active(true);
          break;
          
        case SDLK_r:
          if (event.keyboard.modifiers & KMOD_SHIFT)
            render_mode = (render_mode + render_mode_count - 1) % render_mode_count;
          else
            render_mode = (render_mode + 1) % render_mode_count;
          GLT_TRACE("render mode: %d", render_mode);
          renderer.set_render_mode(render_mode);
          break;

        case SDLK_UP:
          move_camera(0, -1);
          break;

        case SDLK_DOWN:
          move_camera(0, 1);
          break;

        case SDLK_RIGHT:
          move_camera(1, 0);
          break;

        case SDLK_LEFT:
          move_camera(-1, 0);
          break;
          
        default:
          break;
        }
      break;

    default:
      break;
    }
}



// event_mouse
//
void GameView::event_mouse ( const Event &event )
{
  switch (event.type)
    {
    case EventType::MouseMotion:
      // WTK_TRACE("mouse motion: %d, %d (%d)",
      //           event.motion.xrel,
      //           event.motion.yrel,
      //           event.motion.state);
      if (event.motion.state & SDL_BUTTON_MMASK)
        {
          CameraControl &c = cam[0];
          c.pitch -= event.motion.yrel;
          c.yaw -= event.motion.xrel;
          c.camera->wgl_camera.set_rotation({
              glm::radians(float(c.pitch)),
              0.f,
              glm::radians(float(c.yaw)),
            });
        }
      else if (event.motion.state & SDL_BUTTON_RMASK)
        {
          move_camera(-event.motion.xrel, -event.motion.yrel);
        }
      break;

    case EventType::MouseButtonDown:
      WTK_TRACE("mouse button down: %d, %d (%d)",
                event.button.x,
                event.button.y,
                event.button.button);
      break;

    case EventType::MouseButtonUp:
      WTK_TRACE("mouse button up: %d, %d (%d)",
                event.button.x,
                event.button.y,
                event.button.button);
      break;

    case EventType::MouseWheel:
      // WTK_TRACE("mouse wheel: %d, %d",
      //           event.wheel.wx,
      //           event.wheel.wy);
      {
        CameraControl &c = cam[0];
        float zoom_fact = 4.f;
        c.zoom = std::clamp(c.zoom - event.wheel.wy, -10, 10);
        GLT_TRACE("zoom: %d", c.zoom);
        c.camera->wgl_camera.set_fov(glm::radians(45.f + float(c.zoom) * zoom_fact));
      }
      break;

    default:
      break;
    }
}



// GameView::move_camera
//
void GameView::move_camera ( int x,
                             int y )
{
  CameraControl &c = cam[0];
  glm::vec3 pos = c.camera->wgl_camera.get_position();
  glm::vec3 move = glm::rotateY(glm::vec3{float(x), 0.f, float(y)}, glm::radians(float(c.yaw)));
  c.camera->wgl_camera.set_position(pos + move);
}


  
// GameView::draw
//
void GameView::draw ( const DrawContext &context )
{
  static bool initialized = false;
  if (!initialized)
    {
      renderer.render_init();

      GLint viewport[4];
      gl.GetIntegerv(GL_VIEWPORT, viewport);
      for (int c = 0; c < n_cameras; ++c)
        {
          cam[c].camera = game.get_camera(c);
          cam[c].camera->set_active(false);
          cam[c].camera->wgl_camera.set_aspect_ratio(float(viewport[2]) / float(viewport[3]));
        }
      cam[active_cam].camera->set_active(true);

      initialized = true;
    }
  renderer.render();      
  frame_count++;
}
